Skip to main content

3-25 1300. 转变数组后最接近目标值的数组和

Date:2022-03-25 07:17:05

标签:

  • 二分查找算法
  • 前缀和

前置问题:

题目:1300. 转变数组后最接近目标值的数组和 ( 中等😕 )

给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。

示例

示例1:

输入:arr = [4,9,3], target = 10
输出:3
解释:当选择 value 为 3 时,数组会变成 [3, 3, 3],和为 9 ,这是最接近 target 的方案。

示例2:

输入:arr = [2,3,5], target = 10
输出:5

示例3:

输入:arr = [60864,25176,27249,21296,20204], target = 56803
输出:11361

分析

重点:

  • prefix[i]前缀和包不包含nums[i]都可以,只要不计算重复

难点:

  • 二分查找法中的边界问题

题解

二分查找

function findBestValue(arr: number[], target: number): number {
arr.sort((a, b) => a - b)

// console.log('[arr]:', arr)

const len = arr.length
const prefix: number[] = new Array(len + 1).fill(0)

for (let i = 1; i <= len; ++i) {
prefix[i] = prefix[i - 1] + arr[i - 1]
}

// console.log('[prefix]:', prefix)

let ans = 0,
diff = target,
max = arr[len - 1]

for (let i = 1; i <= max; ++i) {
let index = binarySearch(arr, i)

// console.log('[index111]:', index)

if (index < 0) {
index = -index - 1
}

const sum = prefix[index] + (len - index) * i
const curr = Math.abs(sum - target)

// console.log('[diff]:', diff, prefix[index], index, i, sum, curr)

if (curr < diff) {
ans = i
diff = curr
}
}

return ans

function binarySearch(nums: number[], target: number): number {
if (nums.length <= 0 || target < nums[0] || target > nums[nums.length - 1]) {
return -1
}

let left = 0,
right = nums.length - 1

while (left <= right) {
const mid = Math.floor((right - left) / 2) + left

const num = nums[mid]

if (target == num) {
return mid
} else if (target > num) {
left = mid + 1
} else {
right = mid - 1
}
}

return -(left + 1)
}
}

使用

function main() {
// const arr = [4, 9, 3],
// target = 10
// const arr = [2, 3, 5],
// target = 10
// const arr = [60864, 25176, 27249, 21296, 20204],
// target = 56803

// [ 20204, 21296, 25176, 27249, 60864 ]

console.log('[]:', findBestValue(arr, target))
}

main()

export {}

扩展1:704. 二分查找

题目:704. 二分查找 ( 简单😄 )

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

示例

示例1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

分析

  • 重点:

    • 二分查找的条件是查找范围不为空,即 left <= right

    • 注意mid的计算方法,mid = (right - left ) / 2 + left,一定要加上left,否则中间值不准确

    • 一些特殊情况,

      • 搜索元素在数组中,则返回对应索引

        例如:[2,3,5],搜索2,则返回0

      • 搜索元素不再数组中,但在其上下区间内,则返回-2、-3、等

        例如:[2,3,5]

        ​ 搜索4,返回-3,

        ​ 搜索2.5,则返回-2

      • 搜索元素不再数组中,也不再上下区间内,则返回-1

        例如:[2,3,5],搜索1,则返回-1

题解

export function binarySearch(nums: number[], target: number): number {
if (nums.length <= 0 || target < nums[0] || target > nums[nums.length - 1]) {
return -1
}

let left = 0,
right = nums.length - 1

while (left <= right) {
const mid = Math.floor((right - left) / 2) + left

const num = nums[mid]

if (target == num) {
return mid
} else if (target > num) {
left = mid + 1
} else {
right = mid - 1
}
}

return -(left + 1)
}

使用

function main() {
const nums = [1, 3, 4, 5, 9]
const target = 8

console.log('[]:', binarySearch(nums, target))
}

// main()

export {}